﻿using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using NetCore.Controllers;
using NetCore.Dtos;
using NetCore.Entities.Needs;
using NetCore.Extensions;
using NetCore.Mail;
using NetCore.Needs;
using NetCore.Needs.Dtos;
using NetCore.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace NetCore.Web.Mvc.Controllers
{
    /// <summary>
    /// 需求收集
    /// </summary>
    public class NeedController : BaseEntityController<Need>
    {
        private readonly INeedAppService _needService;
        private readonly INeedAttachmentAppService _needAttachmentService;
        private IConfiguration _configuration;
        public NeedController(INeedAppService needService,
            INeedAttachmentAppService needAttachmentService) : base(needService)
        {
            _needService = needService;
            _needAttachmentService = needAttachmentService;
            _configuration = CustomConfigurationManager.Configuration;
        }

        public IActionResult Index()

        {
            return View();
        }
        [HttpGet]
        public async Task<IActionResult> Get(DataSourceLoadOptions loadOptions)
        {
            var result = await _needService.Grid();//从数据库找出的Iqurable 对象，没有执行sql
            return DJson(DataSourceLoader.Load(result, loadOptions));//.data.ToDynamicListAsync()
            //result是Iqurable 对象  result通过在Load返回 Djson一个复杂对象时，其中data为IEnumerable，json化data属性，时执行sql？
            //最终是执行了sql把数据放在了内存 然后再把数据给data，返回 所以 DataSourceLoader.Load(result, loadOptions).data.Tolist() 更好？
            //data为IEnumberable就是方便使用迭代器，这种方式在这里的好处就是前端取10条数据  就是一条一条获取，而不是10条一下子获取？
        }
        [HttpGet]
        public IActionResult Add()
        {
            return View();
        }
        [HttpGet]
        public IActionResult Create()
        {
            return View();
        }

        // POST: Need/Create  上传文件放在参数里面自动匹配了
        //[Consumes("application/json", "multipart/form-data")]//Request.Form.Files获得文件数据 
        [HttpPost]
        public async Task<IActionResult> Create(NeedCreateDto model, string code)
        {
            try
            {
                // 验证码
                //_logger.LogDebug($"{nameof(NeedController)} 准备验证码.....");
                if (!code.Equals(base.HttpContext.Session.GetString("CheckCode"), StringComparison.CurrentCultureIgnoreCase))
                {
                    //_logger.LogDebug($"{nameof(NeedController)} 验证码错误.....");
                    return BadRequest("验证码错误");
                }
                //自定义的上传文件最多21个...
                //model.AddFiles();

                var record = new Need
                {
                    Name = model.Name,
                    Sex = model.Sex,
                    Email = model.Email,
                    Phone = model.Phone,
                    QNumber = model.QNumber,
                    Requirements = model.Requirements
                };
                record = await _needService.InsertAsync(record);//record update 到数据库之后获取record.Id

                var mailModel = new MailDto(_configuration["Mail:SmtpHost"],
                    _configuration["Mail:UserName"], _configuration["Mail:License"],
                    _configuration["Mail:MailFrom"], _configuration["Mail:MailTo"],
                    Convert.ToInt32(_configuration["Mail:Port"]))
                {
                    Cc = _configuration["Mail:MailCC"],
                    Subject = record.Name + _configuration["Mail:Subject"],
                    Body = GetMailBody(record)
                };
                //record.Attachments = model.Attachments;
                //上传的附件，循环赋值 model.UploadFiles或者 Request.Form.Files
                var targetPath = $"{ CustomConfigurationManager.WebRootPath}\\upload\\{record.Id}\\";//\\{model.UploadGuid}
                if (FileExtension.CreateFolderIfNeeded(targetPath))
                {
                    var attatchments = new List<NeedAttachment>();
                    //Request.Form.Files["files1"]
                    var files = model.Files.Where(m => m != null).ToList();
                    foreach (var file in files)
                    {
                        var path = Path.Combine(targetPath, file.FileName);
                        FileExtension.SavaFile(file, path);
                        //添加attachments 并设置record 的attachments
                        attatchments.Add(new NeedAttachment
                        {
                            NeedId = record.Id,
                            FilePath = path
                        });
                        mailModel.AttachmentPaths.Add(path);
                    }
                    if (attatchments.Any())
                    {
                        attatchments.ForEach(m => record.Attachments.Add(m));
                        //_needAttachmentService.Insert(attatchments);
                    }
                }
                //send to mplh
                var mail = new MailService(mailModel);
                await mail.SendAsync();

                //send to customer
                mailModel.To = record.Email.Trim();
                mailModel.Body = GetMailBody(record, true);
                await mail.SendAsync(mailModel);

                return DJson(new Message { Status = true, Url = Url.Action("Index", "Need"), Msg = "保存成功！" });
            }
            catch (Exception e)
            {
                //_logger.LogError($"{nameof(NeedService)} {e.Message},保存失败.....");
                return BadRequest($"{nameof(NeedAppService)} {e.Message},保存失败.....");
            }
        }
        /// <summary>
        /// body里面可以构造html
        /// </summary>
        /// <param name="record"></param>
        /// <param name="sendToCustomer"></param>
        /// <returns></returns>
        private string GetMailBody(Need record, bool sendToCustomer = false)
        {
            var settings = System.Configuration.ConfigurationManager.AppSettings;
            var title = settings["MailTitle"];
            var sign = settings["Sign"];
            var note = "";
            var url = "";
            if (sendToCustomer)
            {
                title = settings["CustomerTitle"] + record.Name + ",\n\n您提交的资料如下：";
                sign = settings["CustomerSign"];
                note = "\n\n您的需求已收到，我们将尽快与您联系！";
                url = "\n\n" + settings["WebsiteUrl"];
            }
            //构造打开邮件自动回调网站的某个action 进行统计

            var body = title + "\n\n姓名：" + record.Name + "\n\n性别：" + record.Sex + "\n\n邮箱：" +
               record.Email + "\n\n电话：" + record.Phone + "\n\nQQ：" + record.QNumber + "\n\n需求：" +
               record.Requirements + note + "\n\n\n\n" + "With Best Regards,\n\n" + sign + url;
            return body;
        }


        /// <summary>
        /// 构造前端html下载标签
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task<string> PopulateAttachements(PopulateAttachementInputDto input)
        {
            var attatchments = await BaseService.GetBaseRepository().GetAll()
                .Where(m => m.Id == input.NeedId)
                .SelectMany(m => m.Attachments).ToListAsync();

            //var isShowDeleteTag = allowDelete;

            var attachmentsString = new StringBuilder();
            //var delList = new List<string>();
            attatchments.ForEach(att =>
            {
                var downloadTag = "<a href='" + Url.Action("Download", "Need", new { id = att.Id }) + "'>" + _needService.GetAttachmentName(att) + "</a>";
                //if (isShowDeleteTag)
                //    downloadTag += "<span data-attatchment-id=\"" + att.Id + "\" class=" + "\"deltag\"" + ">x</span>";
                attachmentsString.Append(downloadTag + ", "); //delList.Add(downloadTag);
            });
            var delStr = attachmentsString.ToString().RemoveLastChar(',');//var delStr = string.Join(",", delList);
            return delStr;
            //return new HtmlString(str);
        }


        /// <summary>
        /// 提供给用户下载
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<IActionResult> Download(InputIdDto input)
        {
            var attachment = _needAttachmentService.Get(input);
            if (attachment?.FilePath is null) return NotFound();
            var filePath = attachment.FilePath;
            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(filePath, FileMode.Open))
            {
                await stream.CopyToAsync(memoryStream);
            }
            memoryStream.Seek(0, SeekOrigin.Begin);
            //文件名必须编码，否则会有特殊字符(如中文)无法在此下载。
            string encodeFilename = HttpUtility.UrlEncode(Path.GetFileName(filePath), Encoding.GetEncoding("UTF-8"));
            base.Response.Headers.Add("Content-Disposition", "attachment; filename=" + encodeFilename);
            return new FileStreamResult(memoryStream, "application/octet-stream");
        }
        /// <summary>
        /// 下载物理文件(给img标签 src属性)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public IActionResult DownloadFile(InputIdDto input)
        {
            var attachment = _needAttachmentService.Get(input);
            if (attachment is null) return null;
            var filePath = attachment.FilePath;
            return PhysicalFile(filePath, "image/jpg", Path.GetFileName(filePath));//PhysicalFile 直接返回物理文件,给href
        }

        /// <summary>
        /// 提供给用户删除文件
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public IActionResult Remove(InputIdDto input)
        {
            var attachment = _needAttachmentService.Get(input);
            if (attachment is null) return null;
            if (System.IO.File.Exists(attachment.FilePath))
            {
                System.IO.File.Delete(attachment.FilePath);
            }
            _needAttachmentService.DeleteAsync(input);
            return SJson();
        }

        [HttpDelete]
        [Description("删除需求数据")]
        public IActionResult Delete()
        {
            var id = GetKey();
            var need = BaseService.GetBaseRepository().GetAll()
                .Include(n => n.Attachments)
                .FirstOrDefault(m => m.Id == id);
            if (need is null)
            {
                return BadRequest("没有找到需求信息~");
            }
            need.Attachments.ToList().ForEach(attachment =>
            {
                if (System.IO.File.Exists(attachment.FilePath))
                {
                    System.IO.File.Delete(attachment.FilePath);
                }
            });
            _needAttachmentService.BulkDeleteEntityAsync(need.Attachments.ToList());
            _needService.DeleteAsync(new InputIdDto { Id = id });
            return SJson();
        }



        /// <summary>
        /// IFormFile uploadFile 前端设置的上传文件名(单文件上传) 多次提交
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult UploadFile(int id)//IFormFile uploadFile 文件过大使用参数获取会出现序列化错误
        {
            try
            {
                var uploadGuid = base.Request.Form["uploadGuid"];
                var need = id > 0 ? _needService.Get(new InputIdDto { Id = id }) : null;
                var order = need != null && need.Attachments.Any() ? need.Attachments.Max(m => m.Order ?? 0) : 0;
                var pathForSaving = $"{CustomConfigurationManager.WebRootPath}{(need != null ? "/upload/need" + need.Id + "/" : "/upload/temp" + uploadGuid + "/")}";
                if (FileExtension.CreateFolderIfNeeded(pathForSaving))
                {
                    //foreach (IFormFile uploadFile in Request.Form.Files)
                    {
                        var uploadFile = Request.Form.Files[0];
                        if (uploadFile != null && uploadFile.Length > 0)
                        {
                            var path = Path.Combine(pathForSaving, uploadFile.FileName);
                            //文件名不重复，当已存在同名文件时，还需要先删除文件
                            //FileExtension.ClearFile(path);
                            FileExtension.SavaFile(uploadFile, path);
                            if (need != null)
                            {
                                need.Attachments.Add(new NeedAttachment
                                {
                                    FilePath = path,
                                    Order = ++order,
                                    NeedId = need.Id,
                                    //OrganizationId = 
                                    //CreatorId = userId
                                });
                            }
                        }
                    }
                }
                return SJson();
            }
            catch (Exception e)
            {
                //throw new Exception(e.Message);
                return EJson(e.Message);
            }
        }

    }
}